﻿//  -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	Smart.Common
//  File name:	RouterService.cs
//  Developer:	Solomatov Igor
//  Created:	15.04.2012
// 
//  -------------------- iSharePoint -------------------- //

using System;

namespace Smart.Common.Router
{
	/// <summary>
	/// Router service
	/// </summary>
	public abstract class RouterService : IRouterService
	{
		/// <summary>
		/// Item of requests' cache
		/// </summary>
		protected class CacheItem
		{
			/// <summary>
			/// Router template name
			/// </summary>
			public string Name { get; set; }

			/// <summary>
			/// Router template
			/// </summary>
			public RouterTemplate Template { get; set; }

			/// <summary>
			/// Last modified cache item date
			/// </summary>
			public object LastValuesKey { get; set; }

			/// <summary>
			/// Last Formattes uri
			/// </summary>
			public string LastFormattedUri { get; set; }
		}

		/// <summary>
		/// Router context
		/// </summary>
		public RouterContext Ctx { get; set; }

		/// <summary>
		/// Current router source (lazy)
		/// </summary>
		public RouterSource Source { get; set; }

		/// <summary>
		/// Current router formatter (lazy)
		/// </summary>
		public RouterFormatter Formatter { get; set; }

		/// <summary>
		/// Get cache entry (path to template and last)
		/// </summary>
		protected CacheEntry<string, CacheItem> GetCacheEntry()
		{
			return
				new CacheEntry<string, CacheItem>(Const.Cache.RouterRequests)
					{
						WebDependent = false,
						UrlDependent = false,
						UserDependent = false,
						Timeout = SPServices.Cache.DefaultTimeout,
						SlidingExpiration = new TimeSpan(0, 5, 0),
						Priority = System.Web.Caching.CacheItemPriority.Low
					};
		}

		/// <summary>
		/// Create router source
		/// </summary>
		public abstract RouterSource CreateSource();

		/// <summary>
		/// Create router formatter
		/// </summary>
		public virtual RouterFormatter CreateFormatter()
		{
			return new RouterFormatter(Ctx);
		}

		/// <summary>
		/// Init router context
		/// </summary>
		public virtual void InitContext(string serviceName)
		{
			Ctx =
				new RouterContext(serviceName)
					{
						Service = this
					};
		}

		/// <summary>
		/// Init service (also fills lazy properties)
		/// </summary>
		public virtual void InitService()
		{
			if (Source == null)
				Source = CreateSource();

			if (Formatter == null)
				Formatter = CreateFormatter();
		}

		/// <summary>
		/// Try to push in context results from cache
		/// </summary>
		protected virtual bool PushResultFromCacheIntoCtx(string name)
		{
			var cacheEntry = GetCacheEntry();

			if (!cacheEntry.ContainsKey(name))
				return false;

			var cacheItem = cacheEntry[name];

			if (cacheItem == null)
				return false;

			Ctx.Template = cacheItem.Template;

			var valuesKey = Source.GetCacheValuesKey();

			if (valuesKey == null)
				return true;

			if (cacheItem.LastValuesKey.ToString().Eq(valuesKey.ToString()))
				Ctx.FormattedUri = cacheItem.LastFormattedUri;

			return true;
		}

		/// <summary>
		/// Put result of uri request to cache
		/// </summary>
		protected virtual void PutResultIntoCacheFromCtx(string name)
		{
			var cacheEntry = GetCacheEntry();

			var cacheItem = cacheEntry[name];

			if (cacheItem == null)
			{
				cacheEntry[name] =
					cacheItem =
					new CacheItem
						{
							Name = name
						};
			}

			cacheItem.Template = Ctx.Template;
			cacheItem.LastValuesKey = Source.GetCacheValuesKey();
			cacheItem.LastFormattedUri = Ctx.FormattedUri;
		}

		/// <summary>
		/// Get formatted uri by name. Ensure that uri corresponds to the real path.
		/// </summary>
		public abstract string GetUri(string name, out string type, params object[] values);

		/// <summary>
		/// Get formatted uri and template type by name. Ensure that uri corresponds to the real path.ary.
		/// </summary>
		public virtual string GetUri(string name, params object[] values)
		{
			string type;

			return GetUri(name, out type, values);
		}

		/// <summary>
		/// Get object specified by name and values
		/// </summary>
		public abstract object Get(string name, params object[] values);

		/// <summary>
		/// Get templated object specified by name and values
		/// </summary>
		public abstract TObjectType Get<TObjectType>(string name, params object[] values)
			where TObjectType : class;

		/// <summary>
		/// Ensure that uri exists
		/// </summary>
		public abstract bool EnsureUriExists(string uri);

		/// <summary>
		/// Add router template to the source if not exists
		/// </summary>
		/// <returns>True if router template doesn't exist and it was added. Otherwise false.</returns>
		public virtual bool AddOrUpdateTemplate(RouterTemplate template)
		{
			return Source.AddRouterTemplate(template);
		}
	}
}